package com.wjm.core;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Data:2022年08月03日
 * Author:wjm
 * Content:
 *
 *
 *  作用：
 *      1）作为服务端的容器，赋值与客户端交互（用来处理请求的）
 *
 *      2）完成与客户端TCP连接
 *
 *      3）基于Http协议，与客户端进行应用交互，使得客户端：浏览器，可以访问到该服务器部署的不同网络应用资源
 *      包括：页面，数据资源，功能等
 *
 *      4）可以管理部署多个不同的网络应用
 *
 */
public class WebServer {
    private ServerSocket serverSocket;


    public WebServer(){
        //通过ServerSocket申请端口号
        try {
            System.out.println("正在申请端口号...");
            serverSocket = new ServerSocket(8080);
            System.out.println("服务器已启动");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * WebServer要执行的必要动作
     */
    public void start(){
        //开启客户端监听
        try {
            /*
                  使用while会出现的两个问题
                      1）数组下标越界
                         java.lang.ArrayIndexOutOfBoundsException
                         原因：Http协议允许客户发送空请求，就是客户端与服务器连接之后，实际上是没有发送任何内容的，但是我们现在
                         是在处理客户端发送过来的所有请求。那么在解析空请求时，就会出现逻辑异常。
                         解决方法：所以我们在解析一个请求时，发现一个空请求，我们应该将异常抛给处理者，对处理者来说，这个异常是允
                         许出现的，但不需要做任何处理。直接与服务端断开连接即可。
                         http://localhost:8080/myweb/index.html
                         http://localhost:8080  这个不是空请求
                         自定义异常：EmptyRequestException（空请求异常）


                      2）资源占用问题
                         当我们请求的资源页面上，还需要加载其他资源时（图片，样式文本，脚步文件等），浏览器会根据指定的路径
                         去发起请求下载这些资源，从而将页面显示完整，一个页面最终肯需要多次请求才能完成显示
                         而使用while循环会创建很多的线程，并且已经加载完毕的线程如果不被销毁，那么cpu会继续为它们分发时间片
                         从而导致后面未执行完成的线程，只有很小的几率获得时间片来执行剩下的任务，导致效率很慢。
                         解决方法：每次执行完请求将socket关闭

            */
            while (true){
                System.out.println("等待客户端连接...");
                //一个socket封装着一个客户端发送过来的所有数据
                Socket socket = serverSocket.accept();
                System.out.println("一个客户端已连接");

                //将socket交给Runnable接口的实现类RequestHandle，来实现多线程
                RequestHandle requestHandle = new RequestHandle(socket);

                /*
                 * 如果有多个客户端同时发送请求，那么我们就需要用多线程来做
                 * */
                //创建线程对象
                Thread thread = new Thread(requestHandle);
                //启动线程
                thread.start();
            }


        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        WebServer webServer = new WebServer();
        webServer.start();
    }

}
